__all__ = ["Item", "items", "removeExpiredItems"]

class ItemManager(object):
    """
    This object will be used as a singleton and enable us to manage the
    instances of the item objects. This means that we will never lose the
    instances.
    """
    def __init__(self):
        """
        Default constructor, ensure that all default attributes are created.
        """
        self.items = {}
    
    def __getitem__(self, name):
        """
        Executed when dictionary retrieval operator ([]) is called upon the
        instantiated singleton object. Assume we want to retrieve the object
        of the item instance represented by the given name. This is a short
        wrapper to the getItem function of this object.
        
        @param str name The name of the item we wish to retrieve
        @return Item|None The Item instnace of the given name.
        """
        return self.getItem(name)
    
    def __contains__(self, name):
        """
        Executed when direct item containmenent is tested upon this object,
        ensure that we return a boolean representing whether or not the said
        item name exists within this object's container.
        
        @param str name The name of the item to test for containment
        @return bool Whether or not the name exists within the item dictionary
        """
        return bool(name in self.items)
    
    def __iter__(self):
        """
        Executed when ths object is iterated through. Ensure that we return an
        iterable object which will create a generator representing the values
        of the item objects.
        
        @return iterator The iterator of the items container
        """
        return self.items.itervalues()
    
    def __delitem__(self, name):
        """
        Executed when the del command is executed upon an subkey of this
        instantiated singleton.
        
        @param str name The name of the item to remove
        """
        self.removeItem(name)
    
    def addItem(self, name):
        """
        Adds an item instance to the in built dictionary container. This allows
        us to ensure that the item instance is stored.
        
        @param str name The name of the item the object represents
        """
        self.items[name] = Item(name)
        return self.items[name]
        
    def getItem(self, name):
        """
        Returns the item instance that this object has stored based on the key
        of the item name.
        
        @param str name The name of the item the object represents
        @return Item|None The Player instnace represented by the user's ID
        """
        return self.items.get(name, None)
    
    def removeItem(self, name):
        """
        Removes an item object from the container. This will remove the instance
        of the object in memory and execute the destructor as long as no other
        instances of the object exists.
        
        @param str name The name of the item to remove
        """
        if name in self:
            del self.items[name]
    
class Item(dict):
    """
    This object will be created for each item object. It will store information
    about the item such as destory upon death, save instance, max buyouts etc.
    """
    def __init__(self, name):
        """
        Default constructor, ensure that all the default attributes are set up
        and assigned.
        
        @param str name The name of the item
        """
        self.name = name
        self.permanent = False
        self.maxCount = 0
        self.appendToUser = True
        self.group = "Miscellaneous"
        self.cost = 0
        self.description = None
        self.aliveToUse = False
        
    def __setitem__(self, item, value):
        """
        Hooks the setitem of the dictionary attribute assignment so generic item
        alteration is impossible. This means we can control which attributes
        are altered.
        
        @param mixed item The key of the object wishing to assign
        @param mixed value The value which the item must be assigned to
        """
        if not isinstance(item, basestring):
            return
        if item == "group":
            self.setGroup(value)
        elif item == "cost":
            self.setCost(value)
        elif item == "description":
            self.setDescription(value)
        elif item == "permanent":
            self.permanent = value
        elif item == "appendToUser":
            self.appendToUser = value
        elif item == "name":
            raise RuntimeError("The name of the item cannot be altered")
            
    def __getitem__(self, item):
        """
        Hooks teh getitem of the dictionary attribute assignment so generic item
        retrieval is impossible and thus allows us to control what values are
        returned.
        
        @param mixed item The key of the object wishing to retrieve
        @return mixed value The value of the key
        """
        if isinstance(item, basestring):
            if item == "group":
                return self.group
            elif item == "cost":
                return self.cost
            elif item == "description":
                return self.description
            elif item == "appendToUser":
                return self.appendToUser
            elif item == "permanent":
                return self.permanent
            elif item == "name":
                return self.name
        raise KeyError("Key %s does not exist in the Items dictionary" % item)
        
    def setDescription(self, description):
        """
        Assigns the item to hold a description value equal to the value passed.
        
        @param str description A description of the item's details
        """
        self.description = description
        
    def setCost(self, cost):
        """
        Assigns a cost value to the item.
        
        @param int cost The amount of dollars that this item will cost
        """
        self.cost = cost
    
    def setGroup(self, groupName):
        """
        Assigns this item to be part of a group
        
        @param str groupName The name of group this item is associated with.
        """
        self.group = groupName
        
    def setMaxCount(self, count):
        """
        Reassigns the maximum value count for the item. This means that the user
        will only be able to purchase this many of this object.
        
        @param int count The amount of these items able to be purchased.
        """
        self.maxCount = count
        
def removeExpiredItems(userid):
    """
    This function will remove any expired items that a user has active. This can
    be seen under the "permanent" attribute of an item object. If the item is
    not permanent (i.e False), then we ned to remove it here. This should be
    called for each player at round end or player death.
    
    @param int userid The ID of the user we wish to remove expired items
    """
    from wcs.libs.players import players
    
    wcsUserid = players[userid]
    if wcsUserid and wcsUserid.items:
        itemsToRemove = set()
        for item in wcsUserid["items"].itervalues():
            if item.name in items and items[item.name].permanent is False:
                itemsToRemove.add(item.name)
        for item in itemsToRemove:
            wcsUserid.removeItem(item)

items = ItemManager()